import java.applet.Applet;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Frame;
import java.awt.GraphicsConfiguration;
import com.sun.j3d.utils.applet.MainFrame; 
import com.sun.j3d.utils.geometry.ColorCube;
import com.sun.j3d.utils.universe.*;
import com.sun.j3d.utils.geometry.*;
import com.sun.j3d.utils.behaviors.mouse.*;
import com.sun.j3d.utils.picking.*;
import javax.media.j3d.TransparencyAttributes;
import java.lang.Object;
import javax.media.j3d.SceneGraphObject;
import javax.media.j3d.NodeComponent;
import javax.media.j3d.*;
import javax.vecmath.*;
import java.awt.event.*;
import java.util.Enumeration;

 
public class Main extends Applet implements MouseListener, MouseMotionListener
{
	
	private PickCanvas pickCanvas;
	
	Color3f green = new Color3f(Color.green);
    Color3f blue = new Color3f(Color.blue);
    Color3f orange = new Color3f(Color.orange);
    Color3f magenta = new Color3f(Color.magenta);
    Color3f black = new Color3f(Color.black);
    Color3f white = new Color3f(Color.white);
    
    Board board;
    
    int turn;
	boolean pass;
	boolean gameOver;
 
 	BranchGroup scene;
 
    public Main() {
    	
       board = new Board('p');
       
       
       
       setLayout(new BorderLayout());
       GraphicsConfiguration config = SimpleUniverse.getPreferredConfiguration();
 
       Canvas3D canvas3D = new Canvas3D(config);
       add("Center", canvas3D);
 
       scene = createSceneGraph();
 
       SimpleUniverse simpleU = new SimpleUniverse(canvas3D);
 
	   simpleU.getViewingPlatform().setNominalViewingTransform();
 
       simpleU.addBranchGraph(scene);
       
       pickCanvas = new PickCanvas(canvas3D, scene);
	   
	   pickCanvas.setMode(PickCanvas.GEOMETRY);

       canvas3D.addMouseListener(this);
       canvas3D.addMouseMotionListener(this);
       
       updateSpheres();
       
       turn = 1;
    	
    }
 
    public static void main(String[] args) {
    	
       Frame frame = new MainFrame(new Main(), 480, 480);
       
       
    }
    
    public BranchGroup createSceneGraph()
    {	
		BranchGroup objRoot = new BranchGroup();
			     
        TransformGroup objTransform = new TransformGroup();
        objTransform.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
        objTransform.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
 
 		objRoot.addChild(objTransform);
 		
 		BoundingSphere boundingSphere = new BoundingSphere(new Point3d(0.0, 0.0, 0.0), 100.0);
   		Background background = new Background(white);    
    	background.setApplicationBounds(boundingSphere);
    	objRoot.addChild(background);
 		
 		
 		int i = 0; 		
        for (float x = -0.7f; x <= 0.7f; x = x + 0.2f, i++)
	    {	
	    	int j = 0;
		    for (float y = -0.7f; y <= 0.7f; y = y + 0.2f, j++)
		    {
		    	int k = 0;
		    	for (float z = -0.7f; z <= 0.7f; z = z + 0.2f, k++)
		   		{
			        Appearance ap = new Appearance();
			        ap.setCapability(Appearance.ALLOW_MATERIAL_READ);
            		ap.setCapability(Appearance.ALLOW_MATERIAL_WRITE);
            		ap.setCapability(Material.ALLOW_COMPONENT_WRITE);
			        
			       	ap.setMaterial(new Material(black, black, black, black, 2.0f));
				   
				   	//	ap.setMaterial(new Material(orange, black, orange, black, 2.0f));
				   	
		      	  	
				 	int primflags = Primitive.GENERATE_NORMALS + Primitive.GENERATE_TEXTURE_COORDS + Primitive.GEOMETRY_NOT_SHARED + Primitive.ENABLE_APPEARANCE_MODIFY;
				  			
		  			Sphere sphere = new Sphere(0.03f, primflags, ap);	
				    TransformGroup tg = new TransformGroup();	
			     	Transform3D transform = new Transform3D();	
			      	Vector3f vector = new Vector3f( x, y, z);	
			      	transform.setTranslation(vector);
			      
			      	sphere.setCapability(Shape3D.ALLOW_APPEARANCE_OVERRIDE_WRITE);
			      	sphere.setCapability(Sphere.ENABLE_APPEARANCE_MODIFY);
			      	sphere.setName(i+" "+j+" "+k+" ");
			      	tg.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);		      	
			      	tg.setTransform(transform);	
			      	tg.addChild(sphere);	
			      	objTransform.addChild(tg);
		    	}
		    }
	   }
 
       MouseRotate myMouseRotate = new MouseRotate();
       myMouseRotate.setTransformGroup(objTransform);
       myMouseRotate.setSchedulingBounds(new BoundingSphere());
       objRoot.addChild(myMouseRotate);
  
       MouseWheelZoom myMouseZoom = new MouseWheelZoom();
       myMouseZoom.setTransformGroup(objTransform);
       myMouseZoom.setSchedulingBounds(new BoundingSphere());
       objRoot.addChild(myMouseZoom);
        
       BoundingSphere bounds = new BoundingSphere(new Point3d(0.0,0.0,0.0), 100.0);
	
	   Vector3f lightDirection = new Vector3f(4.0f, -7.0f, -12.0f);
	
	   DirectionalLight light = new DirectionalLight(white, lightDirection);
	
	   light.setInfluencingBounds(bounds);
	
	   objRoot.addChild(light);
 
       objRoot.compile();
 
	return objRoot;
    }
    
    public void updateSpheres()
    {
    	Enumeration e = scene.getAllChildren();
    	
    	Enumeration i = ((TransformGroup)((Node)e.nextElement())).getAllChildren();
    	
    	while(i.hasMoreElements())
    	{
    		Enumeration j = ((TransformGroup)((Node)i.nextElement())).getAllChildren();
    		while(j.hasMoreElements())
    		{
    			Primitive p = (Primitive)((Node)j.nextElement());
    			Appearance ap = new Appearance();
    			
    			int[] cords = new int[3];
		   		cords[0] = (int)((char)p.getName().charAt(0)) - 48;
		   		cords[1] = (int)((char)p.getName().charAt(2)) - 48;
		   		cords[2] = (int)((char)p.getName().charAt(4)) - 48;
		   		
		   		//System.out.println(p.getName());
		   		
		   		//System.out.println(cords[0]+" "+cords[1]+" "+cords[2]);
    			
    			if(board.stateAt(cords[0], cords[1], cords[2]) == 'o')
    			{
    				TransparencyAttributes t_attr = new TransparencyAttributes(TransparencyAttributes.BLENDED,0.6f);
					ap.setTransparencyAttributes( t_attr ); 
    				ap.setMaterial(new Material(magenta, black, magenta, black, 2.0f));
    			}
    			else if(board.stateAt(cords[0], cords[1], cords[2]) == 'x')
    			{
    				ap.setMaterial(new Material(orange, black, orange, black, 2.0f));
    				board.board[cords[0]][cords[1]][cords[2]] = 'o';
    			}
    			else if(board.stateAt(cords[0], cords[1], cords[2]) == 'g')
    				ap.setMaterial(new Material(green, black, green, black, 2.0f));
    			else if(board.stateAt(cords[0], cords[1], cords[2]) == 'b')
    				ap.setMaterial(new Material(blue, black, blue, black, 2.0f));
    				
    				
    			 
    				
    			p.setAppearance(ap);
    			
    		}
    		
    	}   
    }
    
    public void mouseMoved(MouseEvent e)//Method to dectect which sphere yer mouse is over, runs too slow tho
    {    	
    	pickCanvas.setShapeLocation(e);	
	    PickResult result = pickCanvas.pickClosest();
	
	    if (result != null)
	    {	    	
	       Primitive p = (Primitive)result.getNode(PickResult.PRIMITIVE);	
	       if (p != null)
		   {
		   		int[] cords = new int[3];
		   		cords[0] = (int)(p.getName().charAt(0)) - 48;
		   		cords[1] = (int)(p.getName().charAt(2)) - 48;
		   		cords[2] = (int)(p.getName().charAt(4)) - 48;
		   		
		   		//board.highlight(cords[0], cords[1], cords[2]);
	       }	      
    	}
    	//updateSpheres();
    	e.consume();   
    }
    
    public void mouseClicked(MouseEvent e)
	{	
	    pickCanvas.setShapeLocation(e);	
	    PickResult result = pickCanvas.pickClosest();
	
	    if(result != null && board.gameType == 'p')
	    {	    	
	       Primitive p = (Primitive)result.getNode(PickResult.PRIMITIVE);	
	       if (p != null)
		   {
		   		int[] cords = new int[3];
		   		cords[0] = (int)(p.getName().charAt(0)) - 48;
		   		cords[1] = (int)(p.getName().charAt(2)) - 48;
		   		cords[2] = (int)(p.getName().charAt(4)) - 48;
		   		
		   		System.out.println(cords[0]+" "+cords[1]+" "+cords[2]);
		   		
		   		if(turn == 1)
		   		{
		   			if(board.makeMove(cords[0], cords[1], cords[2], 'g'))
		   				turn = 2;
		   		}
		   		else if(turn == 2)
		   		{
		   			if(board.makeMove(cords[0], cords[1], cords[2], 'b'))
		   				turn = 1;
		   		}
		   		
		   		updateSpheres();
	       }	      
    	}
    	else if(board.gameType == 'c')
    	{
    		if(turn == 1)
		   	{
		   				   		
		   		//if(board.makeMove(cords[0], cords[1], cords[2], 'g'))
		   				turn = 2;
		   	}
		   	else if(turn == 2)
		   	{
		   		//if(board.makeMove(cords[0], cords[1], cords[2], 'b'))
		   				turn = 1;
		   	}
    	}
    	e.consume();  
	}
	
	public void mouseReleased(MouseEvent e){ e.consume(); }
	
	public void mouseExited(MouseEvent e){ e.consume(); }
	
	public void mouseEntered(MouseEvent e){ e.consume(); }
	
	public void mousePressed(MouseEvent e){ e.consume(); }
	
	public void mouseDragged(MouseEvent e){ e.consume(); }
		
}